package demoMod.anm2editor.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import demoMod.anm2editor.fonts.FontKeys;
import demoMod.anm2editor.localization.LocalizedStrings;
import demoMod.anm2editor.model.Animation;
import demoMod.anm2editor.model.Event;
import demoMod.anm2editor.model.Operation;
import demoMod.anm2editor.model.Project;
import demoMod.anm2editor.utils.IdGenerator;
import demoMod.gdxform.abstracts.Container;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.helpers.FontHelper;
import demoMod.gdxform.interfaces.Element;
import demoMod.gdxform.interfaces.MouseEventSubscriber;
import demoMod.gdxform.ui.GLabel;
import demoMod.gdxform.ui.GMenuItem;
import demoMod.gdxform.ui.GMenuList;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EventItem implements Element, MouseEventSubscriber {
    private Container<? extends Element> parent;
    private String id = "";
    private final Event event;
    private final GLabel eventName;
    private final EventPane eventPane = (EventPane) FormManager.getInstance().getContainerById(EventPane.ID);
    private final Timeline timeline = (Timeline) FormManager.getInstance().getContainerById(Timeline.ID);

    public EventItem(float width, float height, Event event, BitmapFont eventNameFont) {
        this.event = event;
        this.eventName = new GLabel(0, eventNameFont.getLineHeight() / 2.0F, width, height, eventNameFont);
        this.eventName.setColor(Color.WHITE.cpy());
        this.eventName.setText(event.getName());
    }

    public Event getEvent() {
        return event;
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public void setId(String id) {
        this.id = id;
    }

    @Override
    public void update() {

    }

    @Override
    public void render(SpriteBatch sb) {
        sb.setColor(Color.WHITE.cpy());
        this.eventName.setX(getX(true) + 5.0F);
        this.eventName.setY(getY(true) + this.eventName.getFont().getLineHeight() / 2.0F);
        this.eventName.render(sb);
    }

    @Override
    public Container<? extends Element> getParent() {
        return parent;
    }

    @Override
    public void setParent(Container<? extends Element> parent) {
        this.parent = parent;
    }

    @Override
    public float getX(boolean isAbsolute) {
        return getParent() != null ? getParent().getX(isAbsolute) : 0;
    }

    @Override
    public float getY(boolean isAbsolute) {
        return getParent() != null ? getParent().getY(isAbsolute) : 0;
    }

    @Override
    public void setX(float v) {

    }

    @Override
    public void setY(float v) {

    }

    @Override
    public float getWidth() {
        return getParent() != null ? getParent().getWidth() : Gdx.graphics.getWidth();
    }

    @Override
    public float getHeight() {
        return getParent() != null ? getParent().getHeight() : Gdx.graphics.getHeight();
    }

    @Override
    public void setWidth(float v) {

    }

    @Override
    public void setHeight(float v) {

    }

    @Override
    public Color getBackground() {
        return null;
    }

    @Override
    public void setBackground(Color color) {

    }

    @Override
    public boolean isResizable() {
        return false;
    }

    @Override
    public void setResizable(boolean b) {

    }

    @Override
    public boolean enabled() {
        return false;
    }

    @Override
    public void setEnabled(boolean b) {

    }

    @Override
    public boolean visible() {
        return false;
    }

    @Override
    public void setVisible(boolean visible) {

    }

    @Override
    public void dispose() {
        this.eventName.dispose();
    }

    @Override
    public boolean clickDown(int screenX, int screenY, int button) {
        if (screenX > getX(true) && screenX < getX(true) + getWidth() && Gdx.graphics.getHeight() - screenY > getY(true)
                && Gdx.graphics.getHeight() - screenY < getY(true) + getHeight()) {
            if (button == Input.Buttons.RIGHT) {
                GMenuList menuList = new GMenuList();
                menuList.setWidth(150.0F);
                menuList.setX(screenX);
                menuList.setY(Gdx.graphics.getHeight() - screenY);
                int index = eventPane.getEventList().indexOf(EventItem.this);
                List<String> strings = LocalizedStrings.getStrings("EventItem");
                GMenuItem newEvent = new GMenuItem(menuList.getWidth(), menuList.getMenuItemHeight(), strings.get(0) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                    @Override
                    public void onClick() {
                        TextInputWindow textInputWindow = new TextInputWindow(strings.get(1), "", FontHelper.getFont(FontKeys.SIM_HEI_14));
                        textInputWindow.setConfirmCallback(name -> {
                            Event event = new Event();
                            event.setId(IdGenerator.nextEventId());
                            event.setName(name);
                            Map<String, List<Integer>> usages = new HashMap<>();
                            for (Animation animation : Project.currentProject.getAnimations()) {
                                usages.put(animation.getName(), new ArrayList<>());
                            }
                            event.setUsages(usages);
                            Project.currentProject.getEvents().add(index, event);
                            EventItem eventItem = new EventItem(getWidth(), ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight(), event, FontHelper.getFont(FontKeys.SIM_HEI_14));
                            eventPane.getEventList().addItem(index - 1, eventItem);
                            eventItem.setId(Integer.toString(event.getId()));
                            if (Project.currentProject.getEvents().size() * eventPane.getEventList().getCellHeight() > eventPane.getScrollPane().getPlainHeight()) {
                                eventPane.getScrollPane().setPlainHeight(eventPane.getScrollPane().getPlainHeight() + eventPane.getEventList().getCellHeight());
                            }
                            Operation operation = new Operation() {
                                @Override
                                public void undo() {
                                    Project.currentProject.getEvents().remove(event);
                                    eventPane.removeEvent(eventItem);
                                    IdGenerator.setEventId(event.getId());
                                    if (Project.currentProject.getEvents().size() * eventPane.getEventList().getCellHeight() < eventPane.getScrollPane().getPlainHeight()
                                            && eventPane.getScrollPane().getPlainHeight() - eventPane.getEventList().getCellHeight() > eventPane.getScrollPane().getHeight()) {
                                        eventPane.getScrollPane().setPlainHeight(eventPane.getScrollPane().getPlainHeight() - eventPane.getEventList().getCellHeight());
                                    }
                                }

                                @Override
                                public void redo() {
                                    Project.currentProject.getEvents().add(index, event);
                                    eventPane.getEventList().addItem(index - 1, eventItem);
                                    IdGenerator.setEventId(event.getId() + 1);
                                    eventItem.setId(Integer.toString(event.getId()));
                                    if (Project.currentProject.getEvents().size() * eventPane.getEventList().getCellHeight() > eventPane.getScrollPane().getPlainHeight()) {
                                        eventPane.getScrollPane().setPlainHeight(eventPane.getScrollPane().getPlainHeight() + eventPane.getEventList().getCellHeight());
                                    }
                                }
                            };
                            operation.setName(strings.get(2));
                            ((HistoryPanel) FormManager.getInstance().getContainerById(HistoryPanel.ID)).addOperation(operation);
                        });
                    }
                };
                GMenuItem renameEvent = new GMenuItem(menuList.getWidth(), menuList.getMenuItemHeight(), strings.get(3) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                    @Override
                    public void onClick() {
                        String nameBefore = event.getName();
                        TextInputWindow textInputWindow = new TextInputWindow(strings.get(4), nameBefore, FontHelper.getFont(FontKeys.SIM_HEI_14));
                        textInputWindow.setConfirmCallback(name -> {
                            if (name.length() > 0) {
                                Operation operation = new Operation() {
                                    @Override
                                    public void undo() {
                                        event.setName(nameBefore);
                                        eventName.setText(nameBefore);
                                    }

                                    @Override
                                    public void redo() {
                                        event.setName(name);
                                        eventName.setText(name);
                                    }
                                };
                                operation.setName(strings.get(5));
                                ((HistoryPanel) FormManager.getInstance().getContainerById(HistoryPanel.ID)).addOperation(operation);
                                event.setName(name);
                                eventName.setText(name);
                            }
                        });
                    }
                };
                GMenuItem deleteEvent = new GMenuItem(menuList.getWidth(), menuList.getMenuItemHeight(), strings.get(6), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                    @Override
                    public void onClick() {
                        EventItem eventItem = eventPane.getEventList().getItem(index);
                        Project.currentProject.getEvents().remove(event);
                        eventPane.removeEvent(EventItem.this);
                        if (Project.currentProject.getEvents().size() * eventPane.getEventList().getCellHeight() < eventPane.getScrollPane().getPlainHeight()
                            && eventPane.getScrollPane().getPlainHeight() - eventPane.getEventList().getCellHeight() > eventPane.getScrollPane().getHeight()) {
                            eventPane.getScrollPane().setPlainHeight(eventPane.getScrollPane().getPlainHeight() - eventPane.getEventList().getCellHeight());
                        }
                        Operation operation = new Operation() {
                            @Override
                            public void undo() {
                                Project.currentProject.getEvents().add(index, event);
                                eventPane.getEventList().addItem(index - 1, eventItem);
                                eventItem.setId(Integer.toString(event.getId()));
                                if (Project.currentProject.getEvents().size() * eventPane.getEventList().getCellHeight() > eventPane.getScrollPane().getPlainHeight()) {
                                    eventPane.getScrollPane().setPlainHeight(eventPane.getScrollPane().getPlainHeight() + eventPane.getEventList().getCellHeight());
                                }
                            }

                            @Override
                            public void redo() {
                                Project.currentProject.getEvents().remove(event);
                                eventPane.removeEvent(EventItem.this);
                                if (Project.currentProject.getEvents().size() * eventPane.getEventList().getCellHeight() < eventPane.getScrollPane().getPlainHeight()
                                        && eventPane.getScrollPane().getPlainHeight() - eventPane.getEventList().getCellHeight() > eventPane.getScrollPane().getHeight()) {
                                    eventPane.getScrollPane().setPlainHeight(eventPane.getScrollPane().getPlainHeight() - eventPane.getEventList().getCellHeight());
                                }
                            }
                        };
                        operation.setName(strings.get(7));
                        ((HistoryPanel) FormManager.getInstance().getContainerById(HistoryPanel.ID)).addOperation(operation);
                    }
                };
                GMenuItem eventManager = new GMenuItem(menuList.getWidth(), menuList.getMenuItemHeight(), strings.get(8), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                    @Override
                    public void onClick() {
                        List<Integer> triggers = event.getUsages().getOrDefault(Project.currentProject.getCurrentAnimation().getName(), new ArrayList<>());
                        boolean used = false;
                        int pointerIndex = timeline.getPointerIndex();
                        for (Integer frameNum : triggers) {
                            if (frameNum == pointerIndex) {
                                used = true;
                                triggers.remove(frameNum);
                                break;
                            }
                        }
                        if (!used) {
                            triggers.add(pointerIndex);
                            event.getUsages().put(Project.currentProject.getCurrentAnimation().getName(),triggers);
                        }
                        final boolean t = used;
                        Operation operation = new Operation() {
                            @Override
                            public void undo() {
                                if (t) {
                                    triggers.add(pointerIndex);
                                    event.getUsages().put(Project.currentProject.getCurrentAnimation().getName(),triggers);
                                } else {
                                    for (Integer frameNum : triggers) {
                                        if (frameNum == pointerIndex) {
                                            triggers.remove(frameNum);
                                            break;
                                        }
                                    }
                                }
                            }

                            @Override
                            public void redo() {
                                if (t) {
                                    for (Integer frameNum : triggers) {
                                        if (frameNum == pointerIndex) {
                                            triggers.remove(frameNum);
                                            break;
                                        }
                                    }
                                } else {
                                    triggers.add(pointerIndex);
                                    event.getUsages().put(Project.currentProject.getCurrentAnimation().getName(),triggers);
                                }
                            }
                        };
                        operation.setName(used ? strings.get(9) : strings.get(10));
                        ((HistoryPanel) FormManager.getInstance().getContainerById(HistoryPanel.ID)).addOperation(operation);
                    }
                };
                eventManager.setSplitLine(false);
                menuList.addElement(newEvent);
                menuList.addElement(renameEvent);
                menuList.addElement(deleteEvent);
                menuList.addElement(eventManager);
                FormManager.getInstance().addContainer(menuList);
                FormManager.getInstance().moveToTop(menuList);
            }
        }
        return false;
    }

    @Override
    public boolean clickUp(int screenX, int screenY, int button) {
        return false;
    }

    @Override
    public boolean mouseDragged(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        return false;
    }

    @Override
    public boolean moveToElementBorder(Element element) {
        return false;
    }
}
